package com.doudou.oauth.config;

import com.doudou.oauth.entity.CacheTokenDto;
import com.doudou.oauth.service.AppUserRoleService;
import com.doudou.oauth.service.MyClientDetailsService;
import com.doudou.oauth.service.MyUserDetailsService;
import com.doudou.oauth.token.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: 傻男人
 * @Date: 2020/5/18 10:11
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class TokenConfig {

    @Value("${security.oauth2.resource.jwt.key-value}")
    private String signingKey;

    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private MyClientDetailsService myClientDetailsService;

    @Autowired
    private OAuth2RequestFactory oAuth2RequestFactory;

    @Autowired
    @Lazy
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * token 增强器
     *
     * @return
     */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(signingKey);
        converter.setAccessTokenConverter(new CustomAccessTokenConverter());
        return converter;
    }

    //配置token模式
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomTokenEnhancer();
    }

    //用于资源服务器
    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }

    /**
     * 授权处理器
     * @param tokenServices
     * @return
     */
    public TokenGranter tokenGranter(AuthorizationServerTokenServices tokenServices) {

        return new TokenGranter() {
            private CompositeTokenGranter delegate;

            @Override
            public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
                if (delegate == null) {
                    delegate = new CompositeTokenGranter(getDefaultTokenGranters(tokenServices));
                }
                OAuth2AccessToken token = delegate.grant(grantType, tokenRequest);
                System.out.println(token);
                redisTemplate.opsForValue().set(token.getAdditionalInformation().get("jti"),new CacheTokenDto(token));
                return token;
            }

            private List<TokenGranter> getDefaultTokenGranters(AuthorizationServerTokenServices tokenServices) {

                AppUserRoleService appUserRoleService = myUserDetailsService;
                UserDetailsService userDetailsService = myUserDetailsService;

                List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
                //改善为简单的授权器
                tokenGranters.add(new SimpleAuthorizationCodeTokenGranter(appUserRoleService,tokenServices, authorizationCodeServices, myClientDetailsService,
                        oAuth2RequestFactory));
                tokenGranters.add(new RefreshTokenGranter(tokenServices, myClientDetailsService, oAuth2RequestFactory));
                ImplicitTokenGranter implicit = new ImplicitTokenGranter(tokenServices, myClientDetailsService, oAuth2RequestFactory);
                tokenGranters.add(implicit);
                tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, myClientDetailsService, oAuth2RequestFactory));
                //支持用户账户获取token
                tokenGranters.add(new ResourceOwnerUserIdTokenGranter(tokenServices,myClientDetailsService,
                        oAuth2RequestFactory,userDetailsService,appUserRoleService));
                //支持app_code获取token
                tokenGranters.add(new AppCodeTokenGranter(tokenServices,myClientDetailsService,
                        oAuth2RequestFactory,userDetailsService,appUserRoleService));

                if (authenticationManager != null) {
                    tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
                            myClientDetailsService, oAuth2RequestFactory));
                }
                return tokenGranters;
            }
        };
    }


}
